package cn.demoframe.test.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * Java 加解密工具类
 */
public class CryptToolkit {

	private static final Logger logger = LoggerFactory.getLogger(CryptToolkit.class);
    private static final String UTF8 = "utf-8";
    //定义 加密算法,可用 DES,DESede,Blowfish
    private static final String ALGORITHM_DESEDE = "DESede";

    private static final String AES = "AES";

    private static String SECRET_PWD = "";

    private static final String hexDigits = "0123456789abcdef";

    static {
        // 获取密钥
        SECRET_PWD = base64Encoder(Constants.ENCRYPTKEY);
    }

    public static String getJavaMD5(String s) {
        try {
            byte[] btInput = s.getBytes();
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();
            // 把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
			for (byte byte0 : md) {
				str[k++] = hexDigits.charAt(byte0 >>> 4 & 0xf);
				str[k++] = hexDigits.charAt(byte0 & 0xf);
			}
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * BASE64 加密
     * @param src 源
     * @return 值
     */
    public static String base64Encoder(String src) {
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(src.getBytes());
    }

    public static String base64Encoder(byte[] bytes) {
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(bytes);
    }

    /**
     * BASE64解密
     *
     * @param dest 待解密字符串
     * @return 解密字符串
     * @throws IOException 异常
     */
    public static String base64Decoder(String dest) throws IOException {
        BASE64Decoder decoder = new BASE64Decoder();
        return new String(decoder.decodeBuffer(dest));
    }

    public static byte[] base64Decoder1(String dest) throws IOException {
        BASE64Decoder decoder = new BASE64Decoder();
        return decoder.decodeBuffer(dest);
    }

    /**
     * 3DES加密
     *
     * @param src 待加密字符串
     * @param key 密钥
     * @return 加密的16进制字符串
     * @throws Exception 异常
     */
    public static String desedeEncoder(String src, String key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(build3DesKey(key), ALGORITHM_DESEDE);
        Cipher cipher = Cipher.getInstance(ALGORITHM_DESEDE);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] b = cipher.doFinal(src.getBytes(UTF8));

        return byte2HexStr(b);
    }

    /**
     * 3DES解密
     *
     * @param dest 目标字符串
     * @param key 密钥
     * @return 解密字符
     * @throws Exception 异常
     */
    public static String desedeDecoder(String dest, String key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(build3DesKey(key), ALGORITHM_DESEDE);
        Cipher cipher = Cipher.getInstance(ALGORITHM_DESEDE);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] b = cipher.doFinal(str2ByteArray(dest));

        return new String(b, UTF8);

    }

    /**
     * 字节数组转化为大写16进制字符串
     *
     * @param b 字节数组
     * @return 16禁止字符串
     */
    private static String byte2HexStr(byte[] b) {
        StringBuilder sb = new StringBuilder();
		for (byte aB : b) {
			String s = Integer.toHexString(aB & 0xFF);
			if (s.length() == 1) {
				sb.append("0");
			}

			sb.append(s.toUpperCase());
		}

        return sb.toString();
    }

    /**
     * 字符串转字节数组
     *
     * @param s 字符
     * @return 字节
     */
    private static byte[] str2ByteArray(String s) {
        int byteArrayLength = s.length()/2;
        byte[] b = new byte[byteArrayLength];
        for (int i = 0; i < byteArrayLength; i++) {
            byte b0 = (byte) Integer.valueOf(s.substring(i*2, i*2+2), 16).intValue();
            b[i] = b0;
        }

        return b;
    }

    /**
     * 构造3DES加解密方法key
     *
     * @param keyStr 密钥
     * @return key
     * @throws UnsupportedEncodingException 异常
     */
    private static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException {
        byte[] key = new byte[24];
        byte[] temp = keyStr.getBytes(UTF8);
        if (key.length > temp.length) {
            System.arraycopy(temp, 0, key, 0, temp.length);
        } else {
            System.arraycopy(temp, 0, key, 0, key.length);
        }

        return key;
    }

    public static String base643DesEncoder(String src, String key) {
		try {
			return base64Encoder(desedeEncoder(src, key));
		} catch (Exception e) {
			logger.error("加密异常", e);
			return null;
		}
    }

    public static String base643DesDecoder(String dest, String key) {
    	try {
			return desedeDecoder(base64Decoder(dest), key);
		} catch (Exception e) {
			logger.error("解密异常", e);
			return null;
		}
    }

    /**
     * SHA-1加密
     * */
    public static String sha1Encrypt(String content) {
	    MessageDigest alg;
		try {
			alg = MessageDigest.getInstance("SHA-1");
			alg.update(content.getBytes());
			byte[] bts = alg.digest();
			String result = "";
			String tmp = "";
            for (byte bt : bts) {
                tmp = (Integer.toHexString(bt & 0xFF));
                if (tmp.length() == 1) {
                    result += "0";
                }
                result += tmp;
            }
			return result;
		} catch (NoSuchAlgorithmException e) {
			logger.error("SHA-1加密异常", e);
			return null;
		}
	}

    /**
     * AES加密
     * <p>返回 Base64 加密结果 code</p>
     * @param content 待加密的内容
     * @return 字节数组转化为大写16进制字符串
     */
    public static String AESEncrypt(String content) {
        String retStr = null;
        try {
            // 用AES算法加密的密钥
            SecretKeySpec key = getKey();
            Cipher cipher = Cipher.getInstance(AES);// 创建密码器
            byte[] byteContent = content.getBytes(UTF8);
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(byteContent);
            retStr = byte2HexStr(result);
        } catch (NoSuchPaddingException e) {
            logger.error("AES加密异常", e);
        } catch (BadPaddingException e) {
            logger.error("AES加密异常", e);
        } catch (NoSuchAlgorithmException e) {
            logger.error("AES加密异常", e);
        } catch (IllegalBlockSizeException e) {
            logger.error("AES加密异常", e);
        } catch (UnsupportedEncodingException e) {
            logger.error("AES加密编码异常", e);
        } catch (InvalidKeyException e) {
            logger.error("AES加密key异常", e);
        }
        return retStr;
    }
    /**
     * AES解密
     * <p>Base64结果解密 </p>
     * @param content 待解密的字节字符组
     * @return 解密后的string
     */
    public static String AESDecrypt(String content) {
        String retStr = null;
        try {
            // 用AES算法加密的密钥
            SecretKeySpec key = getKey();
            // 对加密内容先进行字符串转字节数组
            byte[] byteContent = str2ByteArray(content);
            // 创建密码器
            Cipher cipher = Cipher.getInstance(AES);
            // 以加密的方式用密钥初始化此 Cipher
            cipher.init(Cipher.DECRYPT_MODE, key);
            // 加密算法对象对加密内容字节数组进行解密
            byte[] byteDecrypt = cipher.doFinal(byteContent);
            retStr = new String(byteDecrypt, UTF8);
        } catch (IllegalBlockSizeException e) {
            logger.error("AES解密异常", e);
        } catch (InvalidKeyException e) {
            logger.error("AES解密key异常", e);
        } catch (BadPaddingException e) {
			try {
				// 用AES算法加密的密钥
	            SecretKeySpec key = getKeyTemp();
	            // 对加密内容先进行字符串转字节数组
	            byte[] byteContent = str2ByteArray(content);
	            // 创建密码器
	            Cipher cipher = Cipher.getInstance(AES);
	            // 以加密的方式用密钥初始化此 Cipher
	            cipher.init(Cipher.DECRYPT_MODE, key);
	            // 加密算法对象对加密内容字节数组进行解密
	            byte[] byteDecrypt = cipher.doFinal(byteContent);
	            retStr = new String(byteDecrypt, UTF8);
			} catch (NoSuchAlgorithmException e1) {
				logger.error("AES temp 解密异常", e);
			} catch (NoSuchPaddingException e1) {
				logger.error("AES temp 解密异常", e1);
			} catch (InvalidKeyException e1) {
				logger.error("AES temp 解密异常", e1);
			} catch (IllegalBlockSizeException e1) {
				logger.error("AES temp 解密异常", e1);
			} catch (BadPaddingException e1) {
				logger.error("AES temp 解密异常", e1);
			} catch (UnsupportedEncodingException e1) {
				logger.error("AES temp 解密异常", e1);
			}
        } catch (NoSuchAlgorithmException e) {
            logger.error("AES解密异常", e);
        } catch (NoSuchPaddingException e) {
            logger.error("AES解密异常", e);
        } catch (UnsupportedEncodingException e) {
            logger.error("AES解密编码异常", e);
        }
        return retStr;
    }

    /**
     * 生成密钥
     *
     * @return SecretKeySpec 用AES算法加密的密钥
     * @throws NoSuchAlgorithmException 异常
     */
    public static SecretKeySpec getKey() throws NoSuchAlgorithmException {
    	SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
    	random.setSeed(SECRET_PWD.getBytes());
        //实例化一个用AES加密算法的密钥生成器
        KeyGenerator kgen = KeyGenerator.getInstance(AES);
        //使用用户提供的密钥明文（SECRET_PWD）初始化此密钥生成器，使其具有确定的密钥大小128字节长
        kgen.init(128, random);

        //生成一个密钥
        SecretKey secretKey = kgen.generateKey();
        //返回基本编码格式的密钥，如果此密钥不支持编码，则返回 null
        byte[] enCodeFormat = secretKey.getEncoded();
        //根据给定的enCodeFormat字节数组构造一个用AES算法加密的密钥
        return new SecretKeySpec(enCodeFormat, AES);
    }
    
    /**
     * 临时用
     */
    public static SecretKeySpec getKeyTemp() throws NoSuchAlgorithmException {
    	SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
    	random.setSeed(base64Encoder("123456").getBytes());
        //实例化一个用AES加密算法的密钥生成器
        KeyGenerator kgen = KeyGenerator.getInstance(AES);
        //使用用户提供的密钥明文（SECRET_PWD）初始化此密钥生成器，使其具有确定的密钥大小128字节长
        kgen.init(128, random);

        //生成一个密钥
        SecretKey secretKey = kgen.generateKey();
        //返回基本编码格式的密钥，如果此密钥不支持编码，则返回 null
        byte[] enCodeFormat = secretKey.getEncoded();
        //根据给定的enCodeFormat字节数组构造一个用AES算法加密的密钥
        return new SecretKeySpec(enCodeFormat, AES);
    }

    public static void main(String[] args) {
        String str = "123admin";
        System.out.println("加密后:" + CryptToolkit.getJavaMD5(CryptToolkit.base643DesEncoder(str, Constants.ENCRYPTKEY)));
    }
}
